package com.hsurosy.domain.strategy.service;

import com.hsurosy.domain.strategy.model.entity.RaffleAwardEntity;
import com.hsurosy.domain.strategy.model.entity.RaffleFactorEntity;
import com.hsurosy.domain.strategy.model.entity.StrategyAwardEntity;
import com.hsurosy.domain.strategy.repository.IStrategyRepository;
import com.hsurosy.domain.strategy.service.armory.IStrategyDispatch;
import com.hsurosy.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import com.hsurosy.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import com.hsurosy.types.enums.ResponseCode;
import com.hsurosy.types.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;

/**
 * @Author Hsu琛君珩
 * @Date 2024-10-17 15:56
 * @Description 抽奖策略抽象类
 * @Version: v1.0.0
 */
@Slf4j
public abstract class AbstractRaffleStrategy implements IRaffleStrategy {

    // 策略仓储服务 -> 用于从数据层获取抽奖策略、奖品和规则的相关信息
    protected IStrategyRepository strategyRepository;
    // 策略调度服务 -> 用于执行具体的抽奖逻辑，隔离具体的抽奖操作
    protected IStrategyDispatch strategyDispatch;
    // 抽奖的责任链 -> 用于前置规则的处理，如黑名单、权重等，确保抽奖前的逻辑能正确执行
    protected final DefaultChainFactory defaultChainFactory;
    // 抽奖的决策树 -> 用于中置的规则过滤，如奖品的次数校验、库存校验和兜底奖品的发放
    protected final DefaultTreeFactory defaultTreeFactory;

    // 构造函数，注入所需的依赖
    public AbstractRaffleStrategy(IStrategyRepository strategyRepository, IStrategyDispatch strategyDispatch, DefaultChainFactory defaultChainFactory, DefaultTreeFactory defaultTreeFactory) {
        this.strategyRepository = strategyRepository;
        this.strategyDispatch = strategyDispatch;
        this.defaultChainFactory = defaultChainFactory;
        this.defaultTreeFactory = defaultTreeFactory;
    }

    /**
     * 执行抽奖逻辑。该方法定义了完整的抽奖流程，包括责任链处理和规则树过滤
     *
     * @param raffleFactorEntity 抽奖因子实体，包含用户信息、策略ID等信息
     * @return 抽中的奖品实体，包含奖品ID和相关配置信息
     */
    @Override
    public RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity) {
        // 1. 参数校验，确保用户ID和策略ID有效
        String userId = raffleFactorEntity.getUserId();
        Long strategyId = raffleFactorEntity.getStrategyId();
        if (null == strategyId || StringUtils.isBlank(userId)) {
            // 如果策略ID或用户ID无效，抛出参数不合法的异常
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        log.info("抽奖策略计算 userId: {} strategyId: {}", userId, strategyId);

        // 2. 责任链抽奖处理【先进行责任链规则处理，比如黑名单、权重抽奖等】
        // 责任链返回的抽奖结果如果是非默认规则（如黑名单、权重等），直接返回，不需要再进行后续的规则校验
        DefaultChainFactory.StrategyAwardVO chainStrategyAwardVO = raffleLogicChain(userId, strategyId);
        log.info("抽奖策略计算-责任链 {} {} {} {}", userId, strategyId, chainStrategyAwardVO.getAwardId(), chainStrategyAwardVO.getLogicModel());

        // 如果责任链返回的不是默认抽奖结果，直接返回该结果
        if (!DefaultChainFactory.LogicModel.RULE_DEFAULT.getCode().equals(chainStrategyAwardVO.getLogicModel())) {
            return buildRaffleAwardEntity(strategyId, chainStrategyAwardVO.getAwardId(), chainStrategyAwardVO.getAwardRuleValue());
        }

        // 3. 规则树抽奖过滤【奖品ID在此会根据抽奖次数判断、库存判断、兜底返回最终的奖品】
        DefaultTreeFactory.StrategyAwardVO treeStrategyAwardVO = raffleLogicTree(userId, strategyId, chainStrategyAwardVO.getAwardId(), raffleFactorEntity.getEndDateTime());
        log.info("抽奖策略计算-规则树 {} {} {} {}", userId, strategyId, treeStrategyAwardVO.getAwardId(), treeStrategyAwardVO.getAwardRuleValue());

        // 4. 返回抽中的实际奖品。最终返回奖品ID和奖品配置信息
        return buildRaffleAwardEntity(strategyId, treeStrategyAwardVO.getAwardId(), treeStrategyAwardVO.getAwardRuleValue());
    }

    /**
     * 构建抽奖奖品实体对象
     *
     * @param strategyId 策略ID，用于定位具体的策略
     * @param awardId 奖品ID，用于定位策略下的具体奖品
     * @param awardConfig 奖品配置，例如奖品的额外信息或描述
     * @return 构建完成的 RaffleAwardEntity 对象，包含奖品的详细信息
     */
    private RaffleAwardEntity buildRaffleAwardEntity(Long strategyId, Integer awardId, String awardConfig) {
        // 从存储库查询策略奖品实体，通过策略ID和奖品ID获取奖品的具体信息
        StrategyAwardEntity strategyAward = strategyRepository.queryStrategyAwardEntity(strategyId, awardId);
        // 使用查询到的奖品信息和传入的配置构建 RaffleAwardEntity 对象
        return RaffleAwardEntity.builder()
                .awardId(awardId) // 设置奖品ID
                .awardTitle(strategyAward.getAwardTitle()) // 设置奖品标题
                .awardConfig(awardConfig) // 设置奖品配置
                .sort(strategyAward.getSort()) // 设置排序字段
                .build();
    }

    /**
     * 抽奖计算，责任链抽象方法
     *
     * @param userId 用户ID
     * @param strategyId 策略ID
     * @return 奖品ID
     */
    public abstract DefaultChainFactory.StrategyAwardVO raffleLogicChain(String userId, Long strategyId);

    /**
     * 抽奖结果过滤，决策时抽象方法
     *
     * @param userId 用户ID
     * @param strategyId 策略ID
     * @param awardId 奖品ID
     * @return 过滤结果【奖品ID，会根据抽奖次数判断、库存判断、兜底返回最终的可获得奖品信息】
     */
    public abstract DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId);

    /**
     * 抽奖结果过滤，决策时抽象方法
     *
     * @param userId 用户ID
     * @param strategyId 策略ID
     * @param awardId 奖品ID
     * @param endDateTime 活动结束时间
     * @return 过滤结果【奖品ID，会根据抽奖次数判断、库存判断、兜底返回最终的可获得奖品信息】
     */
    public abstract DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId, Date endDateTime);

}
